/**
* Copyright 2008 - 2015 The Loon Game Engine Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.5
*/
package loon.html5.gwt;
import loon.Graphics;
import loon.LTexture;
import loon.canvas.Image;
import loon.canvas.ImageImpl;
import loon.canvas.LColor;
import loon.canvas.Pattern;
import loon.geom.Affine2f;
import loon.jni.EventHandler;
import loon.utils.MathUtils;
import loon.utils.Scale;
import loon.utils.reply.GoFuture;
import loon.utils.reply.GoPromise;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.CanvasPixelArray;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.ImageData;
import com.google.gwt.dom.client.CanvasElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.NativeEvent;
public class GWTImage extends ImageImpl {
private static native boolean isComplete(ImageElement img) /*-{
return img.complete;
}-*/;
private static native void setComplete(ImageElement img) /*-{
img.complete = true;
}-*/;
public static ImageData scaleImage(ImageElement image, float scale) {
return scaleImage(image, scale, scale);
}
public static ImageData scaleImage(ImageElement image, float scaleToRatioh,
float scaleToRatiow) {
Canvas canvasTmp = Canvas.createIfSupported();
Context2d context = canvasTmp.getContext2d();
float ch = (image.getHeight() * scaleToRatioh);
float cw = (image.getWidth() * scaleToRatiow);
canvasTmp.setCoordinateSpaceHeight((int) ch);
canvasTmp.setCoordinateSpaceWidth((int) cw);
float sx = 0;
float sy = 0;
float sw = image.getWidth();
float sh = image.getHeight();
float dx = 0;
float dy = 0;
float dw = image.getWidth();
float dh = image.getHeight();
context.scale(scaleToRatioh, scaleToRatiow);
context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
float w = dw * scaleToRatioh;
float h = dh * scaleToRatiow;
ImageData imageData = context.getImageData(0, 0, w, h);
return imageData;
}
private ImageElement img;
CanvasElement canvas;
public GWTImage(Graphics gfx, Scale scale, CanvasElement elem, String source) {
super(gfx, scale, elem.getWidth(), elem.getHeight(), source, elem);
this.canvas = elem;
}
public GWTImage(Graphics gfx, Scale scale, ImageElement elem, String source) {
super(gfx, GoPromise.<Image> create(), scale, elem.getWidth(), elem
.getHeight(), source);
img = elem;
final GoPromise<Image> pstate = ((GoPromise<Image>) state);
if (isComplete(img)) {
pstate.succeed(this);
} else {
GWTInputMake.addEventListener(img, "load", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
pixelWidth = img.getWidth();
pixelHeight = img.getHeight();
pstate.succeed(GWTImage.this);
}
}, false);
GWTInputMake.addEventListener(img, "error", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
pstate.fail(new RuntimeException("Error loading image "
+ img.getSrc()));
}
}, false);
}
}
public GWTImage(Graphics gfx, Throwable error) {
super(gfx, GoFuture.<Image> failure(error), Scale.ONE, 50, 50,
"<error>");
setBitmap(createErrorBitmap(pixelWidth, pixelHeight));
}
public ImageElement imageElement() {
return img;
}
GWTImage preload(int prePixelWidth, int prePixelHeight) {
pixelWidth = prePixelWidth;
pixelHeight = prePixelHeight;
return this;
}
@Override
public Pattern createPattern(boolean repeatX, boolean repeatY) {
assert isLoaded() : "Cannot createPattern() a non-ready image";
return new GWTPattern(img, repeatX, repeatY);
}
private void createCanvas() {
if (canvas == null) {
canvas = img.getOwnerDocument().createCanvasElement();
canvas.setHeight(img.getHeight());
canvas.setWidth(img.getWidth());
canvas.getContext2d().drawImage(img, 0, 0);
}
}
@Override
public void getRGB(int startX, int startY, int width, int height,
int[] rgbArray, int offset, int scanSize) {
assert isLoaded() : "Cannot getRgb() a non-ready image";
if (width <= 0 || height <= 0) {
return;
}
createCanvas();
Context2d ctx = canvas.getContext2d();
ImageData imageData = ctx.getImageData(startX, startY, width, height);
CanvasPixelArray pixelData = imageData.getData();
int i = 0;
int dst = offset;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = pixelData.get(i++);
int g = pixelData.get(i++);
int b = pixelData.get(i++);
int a = pixelData.get(i++);
rgbArray[dst + x] = a << 24 | r << 16 | g << 8 | b;
}
dst += scanSize;
}
}
@Override
public void setRGB(int startX, int startY, int width, int height,
int[] rgbArray, int offset, int scanSize) {
if (width <= 0 || height <= 0) {
return;
}
createCanvas();
Context2d ctx = canvas.getContext2d();
ImageData imageData = ctx.createImageData(width, height);
CanvasPixelArray pixelData = imageData.getData();
int i = 0;
int dst = offset;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int argb = rgbArray[dst + x];
pixelData.set(i++, (argb >> 16) & 255);
pixelData.set(i++, (argb >> 8) & 255);
pixelData.set(i++, (argb) & 255);
pixelData.set(i++, (argb >> 24) & 255);
}
dst += scanSize;
}
ctx.putImageData(imageData, startX, startY);
}
@Override
public Image transform(BitmapTransformer xform) {
return new GWTImage(gfx, scale,
((GWTTransformer) xform).transform(img), source);
}
@Override
public void draw(Object ctx, float x, float y, float width, float height) {
((Context2d) ctx).drawImage(img, x, y, width, height);
}
@Override
public void draw(Object ctx, float dx, float dy, float dw, float dh,
float sx, float sy, float sw, float sh) {
Context2d context = (Context2d) ctx;
float f = scale().factor;
sx *= f;
sy *= f;
sw *= f;
sh *= f;
float scaleX = dw / (sw - sx), scaleY = dh / (sh - sy);
context.save();
context.rect(MathUtils.ifloor(dx), MathUtils.ifloor(dy),
MathUtils.iceil(dw), MathUtils.iceil(dh));
context.clip();
Affine2f affine = new Affine2f(scaleX, 0f, 0f, scaleY,
dx - sx * scaleX, dy - sy * scaleY);
context.transform(affine.m00, affine.m01, affine.m10, affine.m11,
affine.tx, affine.ty);
context.drawImage(img, 0, 0);
context.restore();
}
@Override
public String toString() {
return "Image[src=" + source + ", scale=" + scale + ", size=" + width()
+ "x" + height() + ", psize=" + pixelWidth + "x" + pixelHeight
+ ", img=" + img + ", canvas=" + canvas + "]";
}
@Override
protected void setBitmap(Object bitmap) {
img = (ImageElement) bitmap;
}
@Override
protected Object createErrorBitmap(int pixelWidth, int pixelHeight) {
ImageElement img = Document.get().createImageElement();
img.setWidth(pixelWidth);
img.setHeight(pixelHeight);
return img;
}
@Override
public void upload(Graphics gfx, LTexture tex) {
if (!isComplete(img)) {
setComplete(img);
}
((GWTGraphics) gfx).updateTexture(tex.getID(), img);
}
public void getLight(Image buffer, int v) {
int width = (int) buffer.width();
int height = (int) buffer.height();
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
int rgbValue = buffer.getRGB(x, y);
if (rgbValue != 0) {
int color = getLight(rgbValue, v);
buffer.setRGB(color, x, y);
}
}
}
}
public int getLight(int color, int v) {
int red = LColor.getRed(color);
int green = LColor.getGreen(color);
int blue = LColor.getBlue(color);
red += v;
green += v;
blue += v;
blue = blue > 255 ? 255 : blue;
red = red > 255 ? 255 : red;
green = green > 255 ? 255 : green;
red = red < 0 ? 0 : red;
green = green < 0 ? 0 : green;
blue = blue < 0 ? 0 : blue;
return LColor.getRGB(red, green, blue);
}
@Override
public int[] getPixels() {
int width = getWidth();
int height = getHeight();
int[] pixels = new int[width * height];
getRGB(0, 0, width, height, pixels, 0, width);
return pixels;
}
@Override
public int[] getPixels(int[] pixels) {
int width = getWidth();
int height = getHeight();
getRGB(0, 0, width, height, pixels, 0, width);
return pixels;
}
@Override
public int[] getPixels(int x, int y, int w, int h) {
int[] pixels = new int[w * h];
getRGB(x, y, w, h, pixels, 0, w);
return pixels;
}
@Override
public int[] getPixels(int offset, int stride, int x, int y, int width,
int height) {
int[] pixels = new int[width * height];
getRGB(x, y, width, height, pixels, offset, stride);
return pixels;
}
@Override
public int[] getPixels(int[] pixels, int offset, int stride, int x, int y,
int width, int height) {
getRGB(x, y, width, height, pixels, offset, stride);
return pixels;
}
@Override
public void setPixels(int[] pixels, int width, int height) {
if (width <= 0 || height <= 0) {
return;
}
createCanvas();
Context2d ctx = canvas.getContext2d();
ImageData imageData = ctx.createImageData(width, height);
CanvasPixelArray pixelData = imageData.getData();
int i = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int argb = pixels[x + y * width];
pixelData.set(i++, (argb >> 16) & 255);
pixelData.set(i++, (argb >> 8) & 255);
pixelData.set(i++, (argb) & 255);
pixelData.set(i++, (argb >> 24) & 255);
}
}
ctx.putImageData(imageData, 0, 0);
}
@Override
public void setPixels(int[] pixels, int offset, int stride, int x, int y,
int width, int height) {
setRGB(x, y, width, height, pixels, 0, width * height);
}
@Override
public int[] setPixels(int[] pixels, int x, int y, int w, int h) {
setRGB(x, y, w, h, pixels, 0, w * h);
return pixels;
}
@Override
public void setPixel(LColor c, int x, int y) {
setPixel(c.getARGB(), x, y);
}
@Override
public void setPixel(int rgb, int x, int y) {
createCanvas();
int width = img.getWidth();
int height = img.getHeight();
Context2d ctx = canvas.getContext2d();
ImageData imageData = ctx.createImageData(width, height);
CanvasPixelArray pixelData = imageData.getData();
byte bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
int rowOffset = y * bytesPerRow;
int colOffset = x * bytesPerPixel;
int pixelDataLoc = rowOffset + colOffset;
pixelData.set(pixelDataLoc + 0, (rgb >> 16) & 255);
pixelData.set(pixelDataLoc + 1, (rgb >> 8) & 255);
pixelData.set(pixelDataLoc + 2, (rgb) & 255);
pixelData.set(pixelDataLoc + 3, (rgb >> 24) & 255);
}
@Override
public int getPixel(int x, int y) {
assert isLoaded() : "Cannot getRgb() a non-ready image";
createCanvas();
Context2d ctx = canvas.getContext2d();
ImageData imageData = ctx.getImageData(0, 0, img.getWidth(),
img.getHeight());
CanvasPixelArray pixelData = imageData.getData();
int width = img.getWidth();
byte bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
int rowOffset = y * bytesPerRow;
int colOffset = x * bytesPerPixel;
int pixelDataLoc = rowOffset + colOffset;
int r = pixelData.get(pixelDataLoc + 0);
int g = pixelData.get(pixelDataLoc + 1);
int b = pixelData.get(pixelDataLoc + 2);
int a = pixelData.get(pixelDataLoc + 3);
return LColor.getARGB(r, g, b, a);
}
@Override
public int getRGB(int x, int y) {
return getPixel(x, y);
}
@Override
public void setRGB(int rgb, int x, int y) {
setRGB(rgb, x, y);
}
@Override
public boolean hasAlpha() {
return true;
}
@Override
public Image getSubImage(int x, int y, int width, int height) {
return Image.drawClipImage(this, width, height, x, y);
}
@Override
protected void closeImpl() {
img = null;
canvas = null;
}
}